package com.polaris.live.ui.party.utils

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Path
import android.graphics.Rect
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.PathInterpolator
import android.widget.FrameLayout
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.ScreenUtils
import com.polaris.live.common.ext.autoDp
import com.polaris.live.common.mvvm.viewmodel.BaseViewModel
import com.polaris.live.common.util.AppCodeUtils
import com.polaris.live.constant.LiveConst
import com.polaris.live.databinding.WidgetGiftGivingAnimBinding
import com.polaris.live.im.sfs.bean.live.SendLiveMessage
import com.polaris.live.im.sfs.bean.live.ext.MessageUserExtBean
import com.polaris.live.im.sfs.bean.live.payload.InviteGiftPayloadBean
import com.polaris.live.resp.bean.GiftGivingAnimationBean
import com.polaris.live.ui.party.widget.seat.bean.BaseSeatBean
import com.polaris.live.utils.image.ImageUtils
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue

/**
 * 送礼动画辅助类
 * @author Created by 天晴 on 2024/5/25 9:40
 * @since 1.0.0
 **/
class GiftGivingAnimationProxy(val viewModel: BaseViewModel, lifecycleOwner: LifecycleOwner) {

    private val queue by lazy {
        ConcurrentLinkedQueue<GiftGivingAnimationBean>()
    }

    fun clearOverTimeQueue() {
        val currentTime = System.currentTimeMillis()
        val iterator = queue.iterator()
        while (iterator.hasNext()) {
            val element = iterator.next()
            if (currentTime - element.timestamp > CLEAR_TIME) {
                iterator.remove()
            }
        }
    }

    private val spectatorRect by lazy {
        val w = ScreenUtils.getScreenWidth()
        val h = ScreenUtils.getScreenHeight()
        RectBean(0, 0, Rect(w / 2, h - 60.autoDp, w / 2, h - 60.autoDp))
    }

    private val centerRect by lazy {
        val w = ScreenUtils.getScreenWidth()
        val h = ScreenUtils.getScreenHeight()
        RectBean(0, 0, Rect(w / 2, h / 2, w / 2, h / 2))
    }

    val IMAGEWIDTH = 40.autoDp   //宽
    val IMAGEHEIGHT = 40.autoDp   //高

    private var group: ViewGroup? = null

    private val addrs = ConcurrentHashMap<String, RectBean>() //存儲屏幕上控件位置

    init {
        lifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    group?.removeAllViews()
                    queue.clear()
                }
            }
        })
    }

    /**
     * 初始化座位坐标
     */
    fun initSeatViewAddr(group: ViewGroup, deviationX: Int, deviationY: Int, vararg dd: Pair<String, View>) {
        this.group = group
        addrs[SPECTATORID] = spectatorRect
        dd.forEach {
            it.second.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    it.second.viewTreeObserver.removeOnGlobalLayoutListener(this)
                    addrs[it.first] = getViewRect(it.second, deviationX, deviationY)
                }
            })
        }
    }

    /**
     * 播放礼物效果
     */
    fun sendGiftEffect(context: Context, sendLiveMessage: SendLiveMessage, userData: List<BaseSeatBean>) {
        //先判断有没有数据
        val tempExt = sendLiveMessage.ext
        val tempPayLoad = sendLiveMessage.payload
        if (tempExt == null || tempPayLoad == null) {
            return
        }
        val ext = tempExt as MessageUserExtBean
        val payload = tempPayLoad as InviteGiftPayloadBean
        if (payload.gift.animationType != 0) {
            return
        }
        val startUser = userData.find { it.userBasicVo?.userId == ext.user.userId }
        var startIndex = SPECTATORID
        if (startUser != null) {
            startIndex = (startUser.seatId + 1).toString()
        }

        val list = mutableListOf<Pair<String, String>>()
        payload.recipientIds?.forEach { us ->
            val toUser = userData.find { it.userBasicVo?.userId == us }
            if (toUser != null) {
                list.add(startIndex to (toUser.seatId + 1).toString())
            }
        }
        sendGift(
            context, sendLiveMessage, *list.toTypedArray()
        )
    }

    fun sendGift(context: Context, sendLiveMessage: SendLiveMessage, vararg path: Pair<String, String>) {
        path.forEach {
            startGiftAnm(context, sendLiveMessage, it)
        }
    }

    private fun startGiftAnm(context: Context, sendLiveMessage: SendLiveMessage, pair: Pair<String, String>) {
        //先判断有没有数据
        val tempExt = sendLiveMessage.ext
        val tempPayLoad = sendLiveMessage.payload
        if (tempExt == null || tempPayLoad == null) {
            return
        }
        val ext = tempExt as MessageUserExtBean
        val payload = tempPayLoad as InviteGiftPayloadBean

        //关注礼物不用飘这个
        if (payload.gift.type == LiveConst.GiftType.FOLLOWER_GIFT) {
            return
        }
        val first = addrs[pair.first]
        val second = addrs[pair.second]
        if (first != null && second != null) {
            var viewBean = queue.poll()
            if (viewBean == null) {
                viewBean = GiftGivingAnimationBean(
                    WidgetGiftGivingAnimBinding.inflate(
                        LayoutInflater.from(context),
                        null,
                        false
                    ), System.currentTimeMillis()
                )
            }
            viewModel.viewModelScope.launch {
                val loadFloatBitmap = payload.gift.pic.let {
                    ImageUtils.loadNetImageBitmap(
                        context,
                        it,
                        40.autoDp,
                        40.autoDp
                    )
                }
                viewBean.bing.image.setImageBitmap(loadFloatBitmap)
                if (payload.giftCount > 1) {
                    viewBean.bing.countTv.text = "x${payload.giftCount / (payload.recipientIds?.size ?: 1)}"
                } else {
                    viewBean.bing.countTv.text = ""
                }
                if (AppCodeUtils.isAR()) {
                    spectatorAnmAR(viewBean, first, second)
                } else {
                    spectatorAnm(viewBean, first, second)
                }

            }

        }
    }

    /**
     * 观众送
     */
    private fun spectatorAnm(viewBean: GiftGivingAnimationBean, first: RectBean, second: RectBean) {
        val view = viewBean.bing.root
        val lp = FrameLayout.LayoutParams(IMAGEWIDTH, IMAGEHEIGHT)
        val index = group?.indexOfChild(view)
        if (index == null || index < 0) {
            group?.addView(view)
        }
        val startX = (first.rect.left + first.rect.right) / 2 - IMAGEWIDTH / 2 + first.deviationX
        val startY = (first.rect.top + first.rect.bottom) / 2 - IMAGEHEIGHT / 2 + first.deviationY
        val centerX = (centerRect.rect.left + centerRect.rect.right) / 2 - IMAGEWIDTH / 2 + centerRect.deviationX
        val centerY = (centerRect.rect.top + centerRect.rect.bottom) / 2 - IMAGEHEIGHT / 2 + centerRect.deviationY
        val endX = (second.rect.left + second.rect.right) / 2 - IMAGEWIDTH / 2 + second.deviationX
        val endY = (second.rect.top + second.rect.bottom) / 2 - IMAGEHEIGHT / 2 + second.deviationY

        lp.topMargin = startY
        lp.leftMargin = startX
        view.layoutParams = lp

        val animatorCenterX = ObjectAnimator.ofFloat(view, "translationX", 0f, (centerX - startX).toFloat())
        val animatorCenterY =
            ObjectAnimator.ofFloat(view, "translationY", 0f, (centerY - startY).toFloat())
        val animatorScaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f)
        val animatoScalerY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 2f)
        val animatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0.5f, 1f)
        animatorCenterX.duration = 500
        animatorCenterY.duration = 500
        animatorScaleX.duration = 500
        animatoScalerY.duration = 500
        animatorAlpha.duration = 500
        val startSet = AnimatorSet()
        startSet.playTogether(animatorCenterX, animatorCenterY, animatorScaleX, animatoScalerY, animatorAlpha)

        val path = Path()
        path.moveTo(0f, 0f) // 起点
        path.quadTo(0f, 1.5f, 1f, 1f)
        val interpolator = PathInterpolator(path)
        val endAnimatorX =
            ObjectAnimator.ofFloat(view, "translationX", (centerX - startX).toFloat(), (endX - startX).toFloat())
        val endAnimatorY =
            ObjectAnimator.ofFloat(view, "translationY", (centerY - startY).toFloat(), (endY - startY).toFloat())
        val endScaleX = ObjectAnimator.ofFloat(view, "scaleX", 2f, 1.3f)
        val endScaleY = ObjectAnimator.ofFloat(view, "scaleY", 2f, 1.3f)
        endAnimatorY.interpolator = interpolator
        endAnimatorX.duration = 600
        endAnimatorY.duration = 600
        endScaleX.duration = 600
        endScaleY.duration = 600
        val animatorCenterSet2 = AnimatorSet()
        animatorCenterSet2.playTogether(endAnimatorX, endAnimatorY, endScaleX, endScaleY)
        animatorCenterSet2.startDelay = 160

        val backAlpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
        backAlpha.duration = 500
        val animatorCenterSet3 = AnimatorSet()
        animatorCenterSet3.playTogether(backAlpha)
        animatorCenterSet3.startDelay = 160

        // 将两组动画结合起来
        val combinedAnimatorSet = AnimatorSet()
        combinedAnimatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                super.onAnimationEnd(animation)
                group?.post {
                    group?.removeView(view)
                }

                if (queue.size < 30) {
                    queue.offer(viewBean)
                }
            }
        })
        combinedAnimatorSet.playSequentially(startSet, animatorCenterSet2, animatorCenterSet3)
        combinedAnimatorSet.start()
    }

    /**
     * 观众送 阿拉伯
     */
    private fun spectatorAnmAR(viewBean: GiftGivingAnimationBean, first: RectBean, second: RectBean) {
        val sw = ScreenUtils.getScreenWidth()

        val view = viewBean.bing.root
        val lp = FrameLayout.LayoutParams(IMAGEWIDTH, IMAGEHEIGHT)
        val index = group?.indexOfChild(view)
        if (index == null || index < 0) {
            group?.addView(view)
        }
        val startX = sw - ((first.rect.left + first.rect.right) / 2 + IMAGEWIDTH / 2) + first.deviationX
        val startY = (first.rect.top + first.rect.bottom) / 2 - IMAGEHEIGHT / 2 + first.deviationY
        val centerX = sw - ((centerRect.rect.left + centerRect.rect.right) / 2 + IMAGEWIDTH / 2) + centerRect.deviationX
        val centerY = (centerRect.rect.top + centerRect.rect.bottom) / 2 - IMAGEHEIGHT / 2 + centerRect.deviationY
        val endX = sw - ((second.rect.left + second.rect.right) / 2 + IMAGEWIDTH / 2) + second.deviationX
        val endY = (second.rect.top + second.rect.bottom) / 2 - IMAGEHEIGHT / 2 + second.deviationY

        lp.topMargin = startY
        lp.rightMargin = startX
        view.layoutParams = lp

        val animatorCenterX = ObjectAnimator.ofFloat(view, "translationX", 0f, (startX - centerX).toFloat())
        val animatorCenterY =
            ObjectAnimator.ofFloat(view, "translationY", 0f, (centerY - startY).toFloat())
        val animatorScaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f)
        val animatoScalerY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 2f)
        val animatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0.5f, 1f)
        animatorCenterX.duration = 500
        animatorCenterY.duration = 500
        animatorScaleX.duration = 500
        animatoScalerY.duration = 500
        animatorAlpha.duration = 500
        val startSet = AnimatorSet()
        startSet.playTogether(animatorCenterX, animatorCenterY, animatorScaleX, animatoScalerY, animatorAlpha)

        val path = Path()
        path.moveTo(0f, 0f) // 起点
        path.quadTo(0f, 1.5f, 1f, 1f)
        val interpolator = PathInterpolator(path)
        val endAnimatorX =
            ObjectAnimator.ofFloat(view, "translationX", (startX - centerX).toFloat(), (startX - endX).toFloat())
        val endAnimatorY =
            ObjectAnimator.ofFloat(view, "translationY", (centerY - startY).toFloat(), (endY - startY).toFloat())
        val endScaleX = ObjectAnimator.ofFloat(view, "scaleX", 2f, 1.3f)
        val endScaleY = ObjectAnimator.ofFloat(view, "scaleY", 2f, 1.3f)
        endAnimatorY.interpolator = interpolator
        endAnimatorX.duration = 600
        endAnimatorY.duration = 600
        endScaleX.duration = 600
        endScaleY.duration = 600
        val animatorCenterSet2 = AnimatorSet()
        animatorCenterSet2.playTogether(endAnimatorX, endAnimatorY, endScaleX, endScaleY)
        animatorCenterSet2.startDelay = 160

        val backAlpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
        backAlpha.duration = 500
        val animatorCenterSet3 = AnimatorSet()
        animatorCenterSet3.playTogether(backAlpha)
        animatorCenterSet3.startDelay = 160

        // 将两组动画结合起来
        val combinedAnimatorSet = AnimatorSet()
        combinedAnimatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                group?.post {
                    group?.removeView(view)
                }
                if (queue.size < 30) {
                    queue.offer(viewBean)
                }
            }
        })
        combinedAnimatorSet.playSequentially(startSet, animatorCenterSet2, animatorCenterSet3)
        combinedAnimatorSet.start()
    }

    private fun startAnm(viewBean: GiftGivingAnimationBean, first: RectBean, second: RectBean) {
        val view = viewBean.bing.root
        val lp = FrameLayout.LayoutParams(IMAGEWIDTH, IMAGEHEIGHT)
        val index = group?.indexOfChild(view)
        if (index == null || index < 0) {
            group?.addView(view)
        }

        val startX = (first.rect.left + first.rect.right) / 2 - IMAGEWIDTH / 2 + first.deviationX
        val startY = (first.rect.top + first.rect.bottom) / 2 - IMAGEHEIGHT / 2 + first.deviationY
        val centerX = (centerRect.rect.left + centerRect.rect.right) / 2 - IMAGEWIDTH / 2 + centerRect.deviationX
        val centerY = (centerRect.rect.top + centerRect.rect.bottom) / 2 - IMAGEHEIGHT / 2 + centerRect.deviationY
        val endX = (second.rect.left + second.rect.right) / 2 - IMAGEWIDTH / 2 + second.deviationX
        val endY = (second.rect.top + second.rect.bottom) / 2 - IMAGEHEIGHT / 2 + second.deviationY



        lp.topMargin = startY
        lp.leftMargin = startX
        view.layoutParams = lp

        val animatorCenterX =
            ObjectAnimator.ofFloat(view, "translationX", view.translationX, (endX - startX).toFloat())
        val animatorCenterY =
            ObjectAnimator.ofFloat(view, "translationY", view.translationY, (endY - startY).toFloat())
        val animatorScaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.5f)
        val animatoScalerY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.5f)
        val animatorAlpha = ObjectAnimator.ofFloat(view, "alpha", 0.2f, 1f)
        animatorCenterX.duration = 600
        animatorCenterY.duration = 600
        animatorScaleX.duration = 600
        animatoScalerY.duration = 600
        animatorAlpha.duration = 600

        val animatorSet = AnimatorSet()
        animatorSet.playTogether(animatorCenterX, animatorCenterY, animatorScaleX, animatoScalerY, animatorAlpha)

        val backAlpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f)
        backAlpha.duration = 500
        val animatorCenterSet3 = AnimatorSet()
        animatorCenterSet3.playTogether(backAlpha)
        animatorCenterSet3.startDelay = 160

        // 将两组动画结合起来
        val combinedAnimatorSet = AnimatorSet()
        combinedAnimatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                group?.post {
                    group?.removeView(view)
                }
                if (queue.size < 30) {
                    queue.offer(viewBean)
                }
            }
        })
        combinedAnimatorSet.playSequentially(animatorSet, animatorCenterSet3)
        combinedAnimatorSet.start()

    }

    private fun getViewRect(view: View, deviationX: Int, deviationY: Int): RectBean {
        val location = IntArray(2)
        view.getLocationOnScreen(location)
        val x = location[0]
        val y = location[1]
        return RectBean(deviationX, deviationY, Rect(x, y, x + view.width, y + view.height))
    }

    companion object {

        const val SPECTATORID = "0"  //观众位置编号
        const val STEPPING = 1      //步进每10ms移动这这个距离
        const val CLEAR_TIME = 30000L
    }

    data class RectBean(
        val deviationX: Int,   //x轴偏移
        val deviationY: Int,   //y轴偏移
        val rect: Rect,
    )
}